package com.yc.cloud.openai.service.impl;

import java.util.HashMap;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.yc.cloud.basic.exception.Asserts;
import com.yc.cloud.basic.utils.RequestUtil;
import com.yc.cloud.openai.dto.request.coze.CozeOauthTokenParam;
import com.yc.cloud.openai.dto.request.coze.CozeRefreshTokenParam;
import com.yc.cloud.openai.dto.request.coze.CozeRunChatWorkflowParam;
import com.yc.cloud.openai.dto.request.coze.CozeRunWorkflowParam;
import com.yc.cloud.openai.enums.CozeGrantTypeEnums;
import com.yc.cloud.openai.response.CozeOauthTokenResp;
import com.yc.cloud.openai.response.CozeRobotInfoResp;
import com.yc.cloud.openai.response.CozeWorkflowRunResp;
import com.yc.cloud.openai.service.CozeService;
import com.yc.cloud.openai.utils.CozeJwtUtils;
import com.yc.cloud.openai.vo.CozeOauthTokenVo;
import com.yc.cloud.openai.vo.CozeRobotInfoVo;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.val;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CozeServiceImpl implements CozeService {

    @Value("${coze.client-id}")
    private String clientId;

    @Value("${coze.client-secret}")
    private String clientSecret;

    @Value("${coze.redirect-uri}")
    private String redirectUri;

    @Value("${coze.jwt.privateKeyPath}")
    private String privateKeyPath;

    @Value("${coze.jwt.appid}")
    private String appid;

    @Value("${coze.jwt.kid}")
    private String kid;

    private static final String BASE_URL = "https://api.coze.cn/api";
    private static final String AUTHORIZE_URL = "https://www.coze.cn/api/permission/oauth2/authorize";

    @Override
    public String getAuthUrl() {
        // 生成7位随机数作为state
        String state = RandomUtil.randomNumbers(7);
        String url = String.format("%s?response_type=code&client_id=%s&redirect_uri=%s&state=%s",
                AUTHORIZE_URL,
                clientId,
                redirectUri,
                state);
        log.info("生成授权URL: {}, state: {}", url, state);
        return url;
    }

    @Override
    public CozeOauthTokenVo oauthToken(CozeOauthTokenParam param) {
        // 构建请求参数
        JSONObject params = new JSONObject();
        if (CozeGrantTypeEnums.JWT_BEARER.getCode().equals(param.getGrantType())) {
            // JWt的grantType比较复杂,前端传入jwt,后台自己包装
            params.set("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
        } else {
            params.set("grant_type", param.getGrantType());
        }
        params.set("client_id", clientId);
        // 根据不同授权类型设置参数
        if (CozeGrantTypeEnums.AUTHORIZATION_CODE.getCode().equals(param.getGrantType())) {
            if (StrUtil.isEmpty(param.getCode())) {
                Asserts.fail("授权码不能为空");
            }
            params.set("code", param.getCode());
            params.set("redirect_uri", redirectUri);
        } else if (CozeGrantTypeEnums.REFRESH_TOKEN.getCode().equals(param.getGrantType())) {
            if (StrUtil.isEmpty(param.getRefreshToken())) {
                Asserts.fail("刷新令牌不能为空");
            }
            params.set("refresh_token", param.getRefreshToken());
        } else if (CozeGrantTypeEnums.JWT_BEARER.getCode().equals(param.getGrantType())) {
            // 生成JWT Token作为Bearer Token
            String jwtToken = CozeJwtUtils.generateJwtToken(appid, kid, privateKeyPath, 300, param.getUsername()); // 5分钟过期
            if (StrUtil.isEmpty(jwtToken)) {
                Asserts.fail("生成JWT Token失败");
                return null;
            }
            clientSecret = jwtToken;
            log.info("使用JWT Token作为Bearer Token: {}", jwtToken);
        }

        // 构建请求头
        HashMap<String, String> headers = new HashMap<>();
        headers.put("Authorization", "Bearer " + clientSecret);
        headers.put("Content-Type", "application/json");

        log.info("获取coze token请求参数: {}", params);

        // 发送POST请求获取access_token
        val url = BASE_URL + "/permission/oauth2/token";
        String result = HttpUtil.createPost(url)
                .addHeaders(headers)
                .body(params.toString())
                .execute()
                .body();

        log.info("获取coze token结果: {}", result);
        val response = JSONUtil.toBean(result, CozeOauthTokenResp.class);

        // 检查响应
        if (response.getAccessToken() != null) {
            String accessToken = response.getAccessToken();
            val vo = new CozeOauthTokenVo();
            vo.setAccessToken(accessToken);
            vo.setExpiresIn(response.getExpiresIn());
            vo.setRefreshToken(response.getRefreshToken());
            log.info("获取token成功: {}", accessToken);
            return vo;
        } else {
            log.error("获取token失败,响应信息: {}", result);
            Asserts.fail(response.getErrorMessage());
        }
        return null;
    }

    @Override
    public Object refreshToken(CozeRefreshTokenParam param) {
        // TODO Auto-generated method stub
        throw new UnsupportedOperationException("Unimplemented method 'refreshToken'");
    }

    @Override
    public CozeRobotInfoVo getRobotInfo(String robotId) {
        if (StrUtil.isEmpty(robotId)) {
            Asserts.fail("机器人ID不能为空");
            return null;
        }

        // 1. 获取访问令牌
        val param = new CozeOauthTokenParam();
        param.setGrantType(CozeGrantTypeEnums.JWT_BEARER.getCode());
        param.setUsername(robotId);

        log.info("开始获取机器人[{}]的访问令牌", robotId);
        var tokenVo = oauthToken(param);
        if (tokenVo == null || StrUtil.isEmpty(tokenVo.getAccessToken())) {
            log.error("获取机器人[{}]的访问令牌失败", robotId);
            Asserts.fail("获取访问令牌失败");
            return null;
        }
        log.info("成功获取机器人[{}]的访问令牌: {}", robotId, tokenVo.getAccessToken());

        try {
            // 2. 构建请求头
            HashMap<String, String> headers = new HashMap<>();
            headers.put("Authorization", "Bearer " + tokenVo.getAccessToken());
            headers.put("Content-Type", "application/json");

            // 3. 发送GET请求获取机器人信息
            val url = BASE_URL + "/v1/bot/get_online_info?bot_id=" + robotId;
            log.info("开始请求机器人信息, URL: {}", url);

            String result = HttpUtil.createGet(url)
                    .addHeaders(headers)
                    .execute()
                    .body();

            log.info("获取机器人[{}]信息结果: {}", robotId, result);

            // 4. 解析响应
            if (StrUtil.isEmpty(result)) {
                log.error("获取机器人[{}]信息失败: 响应为空", robotId);
                Asserts.fail("获取机器人信息失败: 响应为空");
                return null;
            }

            val response = JSONUtil.toBean(result, CozeRobotInfoResp.class);

            // 处理错误码
            if (response.getCode() != 0) {
                String errorMsg = String.format("获取机器人信息失败[%d]: %s",
                        response.getCode(), response.getMsg());
                log.error("获取机器人[{}]信息失败: {}", robotId, errorMsg);

                // 特殊错误码处理
                if (response.getCode() == 700012006) {
                    errorMsg = "访问令牌无效，请重新授权";
                }

                Asserts.fail(errorMsg);
                return null;
            }

            // 5. 转换为VO对象
            val robotInfo = new CozeRobotInfoVo();
            val data = response.getData();
            robotInfo.setBotId(data.getBotId());
            robotInfo.setName(data.getName());
            robotInfo.setAvatar(data.getIconUrl());
            robotInfo.setDescription(data.getDescription());
            robotInfo.setOnline(true); // API 没有返回在线状态，默认为 true

            log.info("成功获取机器人[{}]信息: {}", robotId, JSONUtil.toJsonStr(robotInfo));
            return robotInfo;

        } catch (Exception e) {
            log.error("获取机器人[{}]信息时发生异常", robotId, e);
            Asserts.fail("获取机器人信息失败: " + e.getMessage());
            return null;
        }
    }

    @Override
    public String runWorkflow(CozeRunWorkflowParam param) {
        try {
            // 1. 构建请求头
            HashMap<String, String> headers = new HashMap<>();
            val tokenParam = new CozeOauthTokenParam();
            tokenParam.setGrantType(CozeGrantTypeEnums.JWT_BEARER.getCode());
            tokenParam.setUsername(param.getUsername());
            val token = oauthToken(tokenParam);
            if (token == null || StrUtil.isEmpty(token.getAccessToken())) {
                Asserts.fail("获取访问令牌失败");
                return null;
            }
            headers.put("Authorization", "Bearer " + token.getAccessToken());
            headers.put("Content-Type", "application/json");

            // 2. 构建请求体
            JSONObject requestBody = new JSONObject();
            requestBody.set("workflow_id", param.getWorkflowId());
            requestBody.set("parameters", param.getParameters());

            // 3. 发送POST请求运行工作流
            val url = BASE_URL + "/v1/workflow/run";
            log.info("开始运行工作流, URL: {}, 参数: {}", url, requestBody);

            String result = HttpUtil.createPost(url)
                    .addHeaders(headers)
                    .body(requestBody.toString())
                    .execute()
                    .body();

            log.info("运行工作流结果: {}", result);

            // 4. 解析响应
            if (StrUtil.isEmpty(result)) {
                log.error("运行工作流失败: 响应为空");
                Asserts.fail("运行工作流失败: 响应为空");
                return null;
            }

            val response = JSONUtil.toBean(result, CozeWorkflowRunResp.class);

            // 处理错误码
            if (response.getCode() != 0) {
                String errorMsg = String.format("运行工作流失败[%d]: %s",
                        response.getCode(), response.getMsg());
                log.error("运行工作流失败: {}", errorMsg);
                Asserts.fail(errorMsg);
                return null;
            }

            // 5. 返回解析后的数据
            return response.getData();
        } catch (Exception e) {
            log.error("运行工作流失败: {}", e.getMessage());
            Asserts.fail("运行工作流失败: " + e.getMessage());
            return null;
        }
    }

    @Override
    public String runChatWorkflow(CozeRunChatWorkflowParam param) {
        try {
            // 1. 构建请求头
            HashMap<String, String> headers = new HashMap<>();
            val tokenParam = new CozeOauthTokenParam();
            tokenParam.setGrantType(CozeGrantTypeEnums.JWT_BEARER.getCode());
            tokenParam.setUsername(param.getUsername());
            val token = oauthToken(tokenParam);
            if (token == null || StrUtil.isEmpty(token.getAccessToken())) {
                Asserts.fail("获取访问令牌失败");
                return null;
            }
            headers.put("Authorization", "Bearer " + token.getAccessToken());
            headers.put("Content-Type", "application/json");

            // 2. 构建请求体
            JSONObject requestBody = new JSONObject();
            requestBody.set("parameters", new JSONObject());
            requestBody.set("workflow_id", "7486423302292340763");
            requestBody.set("bot_id", "7479037660318269475");
            requestBody.set("conversation_id", param.getConversationId());
            
            // 构建消息
            JSONArray messages = new JSONArray();
            JSONObject message = new JSONObject();
            message.set("content", "你好");
            message.set("content_type", "text");
            message.set("role", "user");
            message.set("type", "question");
            messages.add(message);
            requestBody.set("additional_messages", messages);

            // 3. 发送POST请求运行对话流
            val url ="https://api.coze.cn/v1/workflows/chat";
            log.info("开始运行对话流, URL: {}, 参数: {}", url, requestBody);

            String result = HttpUtil.createPost(url)
                    .addHeaders(headers)
                    .body(requestBody.toString())
                    .execute()
                    .body();

            log.info("运行对话流结果: {}", result);

            // 4. 解析响应
            if (StrUtil.isEmpty(result)) {
                log.error("运行对话流失败: 响应为空");
                Asserts.fail("运行对话流失败: 响应为空");
                return null;
            }

            val response = JSONUtil.toBean(result, CozeWorkflowRunResp.class);

            // 处理错误码
            if (response.getCode() != 0) {
                String errorMsg = String.format("运行对话流失败[%d]: %s",
                        response.getCode(), response.getMsg());
                log.error("运行对话流失败: {}", errorMsg);
                Asserts.fail(errorMsg);
                return null;
            }

            // 5. 返回解析后的数据
            return response.getData();
        } catch (Exception e) {
            log.error("运行对话流失败: {}", e.getMessage());
            Asserts.fail("运行对话流失败: " + e.getMessage());
            return null;
        }
    }

}
